<?php
/**
* phpCan - http://idc.anavallasuiza.com/
*
* phpCan is released under the GNU Affero GPL version 3
*
* More information at license.txt
*/

defined('ANS') or die();

class Config implements ArrayAccess, Iterator, Countable {
	public $config = array();

	private $Debug;


	/**
	 * public function __construct (void)
	 *
	 * return none
	 */
	public function __construct () {
		global $Debug;

		$this->Debug = $Debug;
	}

	/**
	 * public function __get (string $name)
	 *
	 * return none
	 */
	public function __get ($name) {
		return $this->config[$name];
	}

	/**
	 * public function __set (string $name, $value)
	 *
	 * return none
	 */
	public function __set ($name, $value) {
		$this->config[$name] = $value;
	}

	/**
	 * ArrayAccess: final public function offsetExists ($offset)
	 *
	 * return boolean
	 */
	final public function offsetExists ($offset) {
		return array_key_exists($offset, $this->config);
	}


	/**
	 * ArrayAccess: final public function offsetGet ($offset)
	 *
	 * return mixed
	 */
	final public function offsetGet ($offset) {
		return $this->config[$offset];
	}


	/**
	 * ArrayAccess: final public function offsetSet ($offset, $value)
	 *
	 * return none
	 */
	final public function offsetSet ($offset, $value) {
		$this->config[$offset] = $value;
	}


	/**
	 * ArrayAccess: final public function offsetUnset ($offset)
	 *
	 * return none
	 */
	final public function offsetUnset ($offset) {
		unset($this->config[$offset]);
	}


	/**
	 * Iterator: final public function current ()
	 *
	 * return mixed
	 */
	final public function current () {
		return current($this->config);
	}


	/**
	 * Iterator: final public function key ()
	 *
	 * return string/int
	 */
	final public function key () {
		return key($this->config);
	}


	/**
	 * Iterator: final public function next ()
	 *
	 * return none
	 */
	final public function next () {
		return next($this->config);
	}


	/**
	 * Iterator: final public function rewind ()
	 *
	 * return none
	 */
	final public function rewind () {
		return reset($this->config);
	}


	/**
	 * Iterator: final public function valid ()
	 *
	 * return none
	 */
	final public function valid () {
		return isset($this->config[key($this->config)]);
	}


	/**
	 * Countable: final public function count ()
	 *
	 * return none
	 */
	final public function count () {
		return count($this->config);
	}


	/**
	 * public function load (string $filename, [string $context], [string $prefix])
	 *
	 * return boolean
	 */
	public function load ($filename, $context = '', $prefix = '') {
		global $Vars;

		if (!$filename) {
			return false;
		}

		if (!$context) {
			$context = $Vars->getModule() ? 'module' : 'scene';
		}

		//Define directories
		$config_dirs = array();

		switch ($context) {
			case 'phpcan':
				$config_dirs[] = PHPCAN_PATH.'config/';
				$config_dirs[] = PHPCAN_PATH.'config/'.DEFAULT_CONFIG_PATH;
				$config_dirs[] = PHPCAN_PATH.'config/'.DOMAIN_CONFIG_PATH;
				break;

			case 'scene':
				if (!$Vars->getScene()) {
					return false;
				}

				$config_dirs[] = SCENE_PATH.'config/';
				$config_dirs[] = SCENE_PATH.'config/'.DEFAULT_CONFIG_PATH;
				$config_dirs[] = SCENE_PATH.'config/'.DOMAIN_CONFIG_PATH;
				break;

			case 'module':
				if (!$Vars->getModule()) {
					return false;
				}

				$config_dirs[] = MODULE_PATH.'config/';
				$config_dirs[] = MODULE_PATH.'config/'.DEFAULT_CONFIG_PATH;
				$config_dirs[] = MODULE_PATH.'config/'.DOMAIN_CONFIG_PATH;
				$config_dirs[] = SCENE_PATH.'config/'.$Vars->getModule().'/';
				$config_dirs[] = SCENE_PATH.'config/'.$Vars->getModule().'/'.DEFAULT_CONFIG_PATH;
				$config_dirs[] = SCENE_PATH.'config/'.$Vars->getModule().'/'.DOMAIN_CONFIG_PATH;
				break;

			default:
				if ($context) {
					$config_dirs[] = $context;
					$config_dirs[] = $context.DEFAULT_CONFIG_PATH;
					$config_dirs[] = $context.DOMAIN_CONFIG_PATH;
				} else {
					return false;
				}
		}

		//Include config files
		$config = array();

		foreach ($config_dirs as $config_dir) {
			if (is_file($config_dir.$filename)) {
				include ($config_dir.$filename);
			}
		}

		if (!$config) {
			return false;
		}

		//Save config
		foreach ($config as $key => $value) {
			$key = $prefix.$key;

			if (is_array($this->config[$key]) && is_array($value)) {
				$this->config[$key] = array_merge($this->config[$key], $value);
			} else {
				$this->config[$key] = $value;
			}

			//Expand config
			$this->config[$key] = $this->expand($this->config[$key]);
		}

		return true;
	}


	/**
	 * private function expand ($data)
	 *
	 * Expand the array config width commas
	 *
	 * return boolean
	 */
	private function expand ($data) {
		if (!is_array($data)) {
			return $data;
		}

		foreach ($data as $key => $value) {
			if (strstr($key, ',')) {
				$keys = explode(',', $key);

				foreach ($keys as $k) {
					$k = trim($k);

					$data[$k] = array_merge_recursive((array)$data[$k], (array)$value);
					$data[$k] = $this->expand($data[$k]);
				}

				unset($data[$key]);
			} else if (is_array($data[$key])) {
				$data[$key] = $this->expand($data[$key]);
			}
		}

		return $data;
	}


	/**
	 * public setCurrentConfig (string $config, [array $preserve])
	 *
	 * Set the config for current controller and exit mode
	 *
	 * return boolean
	 */
	public function setRouteConfig ($config, $preserve = array()) {
		global $Vars;

		if (!$Vars->route_config) {
			return false;
		}

		$route_config = array();
		$exit_mode = $Vars->getExitMode();

		foreach ($Vars->route_config as $route) {
			if (!$route) {
				continue;
			}

			foreach ($route as $config_name => $config_value) {

				if (strpos($config_name, '#')) {
					list($config_name, $config_exit_mode) = explode('#', $config_name, 2);

					if ((trim($config_name) != $config) || ($config_exit_mode != $exit_mode)) {
						continue;
					}
				} else if ($config_name != $config) {
					continue;
				}

				$route_config[] = (array)$config_value;
			}
		}

		$new_config = call_user_func_array('arrayMergeReplaceRecursive', $route_config);

		if ($preserve) {
			foreach ($preserve as $name) {
				$preserve_config = array();

				foreach ($route_config as $value_config) {
					if ($value_config[$name]) {
						$preserve_config[] = (array)$value_config[$name];
					}
				}

				if ($preserve_config) {
					$new_config[$name] = call_user_func_array('arrayMergeReplaceRecursive', $preserve_config);
				}
			}
		}

		if ($new_config) {
			ksort($new_config, SORT_STRING);

			$this->config[$config] = $new_config;
		} else {
			$this->config[$config] = array();
		}

		return true;
	}
}
?>
